# 神经网络优化，使用正则化减少过拟合，使用优化器更新网络参数
## 1 预备知识
### 1.1
# import tensorflow as tf
#
# a = tf.constant([1, 2, 3, 1, 1])
# b = tf.constant([0, 1, 3, 4, 5])
# c = tf.where(tf.greater(a,b), a, b)
# print(c)

### 1.2
import numpy as np

# rdm = np.random.RandomState(seed=1)
# a = rdm.rand()
# b = rdm.rand(2,3)
# print(a)
# print(b)

### 1.3 将2个数组在垂直方向叠加
# a = np.array([1, 2, 3])
# b = np.array([4, 5, 6])
# c = np.vstack((a,b))
# print(c)

### 1.4
# x,y = np.mgrid[1:3:1, 2:4:0.5]      #通过指定切片来生成网格
# print(x)
# print(y)
# print(x.ravel())
# print(y.ravel())
# grid = np.c_[x.ravel(), y.ravel()]  #生成网格坐标点
# print(grid)

# #网格可视化
# from matplotlib import pyplot as plt
# # 将网格展平以绘制点
# plt.scatter(x.ravel(), y.ravel(), color='blue')
# # 设置坐标轴范围和标签
# plt.xlim(0.5, 3.5)
# plt.ylim(1.5, 4.5)
# plt.xlabel('X 轴')
# plt.ylabel('Y 轴')
# # 显示网格
# # plt.grid(True)
# plt.grid(False)
# # 显示图形
# plt.show()


## 2 神经网络(NN)复杂度
'''
NN复杂度：多用NN层数和NN参数的个数表示
eg.  shape[3, 4, 2]
空间复杂度：所有参与运算的层数: 3*4+4  +  4*2+2  =  26
时间复杂度：运算的次数: 3*4  +  4*2  =  20
'''

## 3 指数衰减学习率
'''
学习率先大后小：先快速得到较优解，在减小学习率让后期训练稳定
指数衰减学习率 = 初始学习率 * 学习率衰减率^（当前轮数/多少轮衰减一次）
epoch = 40
LR_base = 0.2
LR_decay = 0.99
LR_step = 1
lr = LR_base * LR_decay**(epoch  / LR_step)
'''

## 4 激活函数
'''
a、Sigmoid函数  tf.nn.sigmoid    1、输出非0均值（收敛慢） 2、有幂运算（训练费时） 3、存在梯度消失
b、Tanh函数 tf.math.tanh(x)      输出0均值，比sigmoid范围大，但仍有幂运算（训练费时），且存在梯度消失
c、Relu函数 tf.nn.relu(x)        dead relu
d、Leaky Relu函数 tf.nn.leaky_relu(x)
e、softmax函数                   将输入转换为概率分布，所有输出之和为1（多类别分类任务的最后一层激活函数）
f、Swish函数 Swish = x * Sigmoid(x)

给初学者的建议：
1、首选relu函数
2、学习率设置较小值
3、输入特征标准化，即让输入特征满足以0为均值，1为标准差的正态分布
4、初始参数中心化，即让随机生成的参数满足以0位均值，开方（2/当前层数输入特征个数）为标准差的正态分布
'''

## 5 损失函数
'''
a、均方差mse  tf.reduce_mean(tf.square(y_ - y))
b、自定义损失函数
c、交叉熵损失函数CE（cross entropy） tf.losses.categorical_crossentropy(y_, y)
d、softmax与交叉熵结合 tf.nn.softmax_cross_entropy_with_logits(y_, y)
'''

## 6 欠拟合与过拟合
'''
欠拟合的解决方法：
    a、增加输入特征项
    b、增加网络参数
    c、减少正则化参数
过拟合的解决方法：
    a、数据清洗
    b、增大训练集
    c、采用正则化
    d、增大正则化参数    
'''

## 7 正则化减少过拟合
'''
正则化：在损失函数中加入一个正则项
正则化的方法：
    a、L1 正则化（Lasso）：大概率使很多参数变为0，可以用此减少参数的数量，降低复杂度
    b、L2 正则化（Ridge）：会使参数很接近0但不为0，可以用此减少参数值大小，降低复杂度
    c、弹性网络正则化（Elastic Net）
    d、 Dropout（主要用于神经网络）
    e、 早停法（Early Stopping）
'''

## 8 优化器更新网络参数
'''
SGD（无momentum），常用的梯度下降法
SGDM（含momentum）
Adagrad
RMSProp，SGD基础上增加二阶动量
Adam,同时结合SGDM一阶动量和RMSProm二阶动量

'''